/**
 * 最小平移向量构建函数
 * @param {VectorB} axis 最小平移向量的单位向量
 * @param {Number} overlap 最小平移向量的模
 */
function MinimumTranslationVector (axis, overlap) {
    this.axis = axis;
    this.overlap = overlap;
}

/**
 * 获取多边形离圆最近的顶点
 * @param {Polygon} polygon 碰撞中的多边形
 * @param {Circle} circle 碰撞中的圆
 */
function getPolygonPointClosestToCircle(polygon, circle) {
    var min = 10000, length, testPoint, closestPoint;
    for(var i = 0; i < polygon.points.length; i += 1) {
        testPoint = polygon.points[i];
        length = Math.sqrt( Math.pow(testPoint.x - circle.x, 2) + Math.pow(testPoint.y - circle.y, 2) );
        if(length < min) {
            min = length;
            closestPoint = testPoint;
        }
    }
    return closestPoint;
}

/**
 * 检测多边形与圆的碰撞
 * @param {Polygon} polygon 碰撞中的多边形
 * @param {Circle} circle 碰撞中的圆
 */
// function polygonCollidesWithCircle (polygon, circle) {
//     var min = 10000, v1, v2, edge, perpendicular, normal,
//         axes = polygon.getAxes(),
//         closestPoint = getPolygonPointClosestToCircle(polygon, circle);
//     v1 = new VectorB(new Point(circle.x, circle.y));
//     v2 = new VectorB(new Point(closestPoint.x, closestPoint.y));
//     axes.push(v1.sub(v2).normalize());
//     return !polygon.separationOnAxes(axes, circle);
// }

/**
 * 获取指定圆与最近点的投影轴
 * @param {Circle} 要获取投影轴的圆
 * @param {Point} 最近顶点
 * @return {VectorB} 投影轴
 */
function getCircleAxis (c, closestPoint) {
    var v1 = new VectorB(new Point(c.x, c.y)),
        v2 = new VectorB(new Point(closestPoint.x, closestPoint.y));
    return v1.sub(v2).normalize();
}

/**
 * 两个多边形之间的碰撞
 * @param {Polygon} p1 主动多边形对象
 * @param {Polygon} p2 受测多边形对象
 * @return {MinimumTranslationVector} 碰撞的最小平移向量
 */
function polygonCollidesWithPolygon (p1, p2) {
    var mtv1 = p1.minimumTranslationVector(p1.getAxes(), p2),
        mtv2 = p2.minimumTranslationVector(p2.getAxes(), p1);
    if(mtv1.overlap === 0 && mtv2.overlap === 0) {
        //没有碰撞
        return new MinimumTranslationVector(undefined, 0);
    } else {
        return mtv1.overlap < mtv2.overlap ? mtv1 : mtv2;
    }
}

/**
 * 两个圆形之间的碰撞
 * @param {Circle} c1 主动圆形
 * @param {Circle} c2 受测圆形
 * @return {MinimumTranslationVector} 碰撞的最小平移量（axis属性始终为undefined)
 */
function circleCollidesWithCircle (c1, c2) {
    var distance = Math.sqrt( Math.pow(c2.x - c1.x, 2) + Math.pow(c2.y - c1.y, 2) ),
        overlap = Math.abs(c1.radius + c2.radius) - distance;
    return overlap < 0 ? new MinimumTranslationVector(undefined, 0) : new MinimumTranslationVector(undefined, overlap);
}

/**
 * 检测多边形与圆之间的碰撞
 * @param {Polygon} p 碰撞中的多边形
 * @param {Circle} c 碰撞中的圆
 * @return {MinimumTranslationVector} 最小平移向量
 */
function polygonCollidesWithCircle (p, c) {
    var axes = p.getAxes(),
        closestPoint = getPolygonPointClosestToCircle(p, c);
    axes.push(getCircleAxis(c, closestPoint));
    return p.minimumTranslationVector(axes, c);
}



/**
 * 最小平移向量的三个作用：
 *  1.将碰撞的两个形状分开
 *  2.让碰撞的两个形状粘连
 *  3.让碰撞的两个形状弹开
 */
/**
 * 将碰撞的两个形状分开
 * @param {Shape} shapeMoving 正在移动的形状独享
 * @param {MinimumTranslationVector} mtv 给入的最小平移向量
 * @param {VectorB} velocity 代表速度
 */
function separate (shapeMoving, mtv, velocity) {
    var dx, dy, velocityMagnitude, point;
    if(mtv.axis === undefined) {
        point = new Point();
        //正在处理圆形
        velocityMagnitude = Math.sqrt( Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2) );
        point.x = velocity.x / velocityMagnitude;
        point.y = velocity.y / velocityMagnitude;

        mtv.axis = new VectorB(point); //构建成功一个代表速度的单位向量
    }

    dy = mtv.axis.y * mtv.overlap;
    dx = mtv.axis.x * mtv.overlap;

    //逆向移动
    if( (dx < 0 && velocity.x < 0) || (dx > 0 && velocity.x > 0) ) {
        dx = -dx;
    }
    if( (dy < 0 && velocity.y < 0) || (dy > 0 && velocity.y > 0) ) {
        dy = -dy;
    }

    shapeMoving.move(dx, dy);
}